﻿#region Using Statemens
using System;
using GameBase.Screens;
using GameBase.Sprites;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using StarFox.ScreenComponents;
#endregion

namespace StarFox.Screens
{
    /// <summary>
    /// Game over screen of the game.
    /// </summary>
    public class GameOverScreen : StarFoxScreen
    {
        #region Screen Transitions

        bool toHidden = false;

        float trTime = 0.0f;

        /// <summary>
        /// Makes the Screen transition to visible state.
        /// </summary>
        public override void Show()
        {
            string[] playList = { "03_GAMEOVER_THEME" };
            PlayList.Start(playList);
            PlayList.Repeat = true;

            base.Show();
        }

        /// <summary>
        /// Makes the Screen transition to hidden state.
        /// </summary>
        public override void Hide()
        {
            toHidden = true;

            base.Hide();
        }

        #endregion

        #region Initialization

        /// <summary>
        /// Initializes a new instance of this class.
        /// </summary>
        /// <param name="screenManager">The ScreenManager that this screen should be attached to.</param>
        public GameOverScreen(ScreenManager screenManager)
            : base(screenManager)
        {
            Name = "GameOverScreen";
        }

        /// <summary>
        /// Called when the Screen needs to be initialized.
        /// </summary>
        public override void Initialize()
        {
            Components3D.Add(new MenuBackground(this) { Duration = TimeSpan.FromSeconds(6) });
            Components2D.Add(new GameOverMenu(this));

            base.Initialize();
        }

        #endregion

        #region Update

        /// <summary>
        /// Called when the Screen needs to be updated.
        /// </summary>
        /// <param name="gameTime">Time elapsed since the last call to this method.</param>
        public override void Update(GameTime gameTime)
        {
            if (toHidden)
            {
                // update transition timer
                float trDelta = (float)(gameTime.ElapsedGameTime.TotalMilliseconds / Time.TotalMilliseconds);
                trTime += trDelta;
                trTime = MathHelper.Clamp(trTime, 0.0f, 1.0f);
                if (trTime == 1.0f) { toHidden = false; trTime = 0.0f; PlayList.Stop(); ScreenSound.LoadGame(); }
            }

            base.Update(gameTime);
        }

        #endregion
    }

    #region GameOverMenu

    internal class GameOverMenu : ScreenComponent2D
    {
        #region Fields

        GameScore gameScore;

        SpriteSheet spriteSheet;
        SpriteFont smallFont;

        // starfox logo
        Rectangle dstRectStarFox;
        Rectangle dstRectXna;

        // menu title
        Point initPosMenuTitle;
        Point endPosMenuTitle;
        Rectangle dstRectMenuTitle;

        // buttons
        Point initPosBtn;
        Point endPosBtn;
        Rectangle dstRectBtn;

        // button messages
        Point initPosBtn_Msg;
        Point endPosBtn_Msg;
        Rectangle dstRectBtn_Msg;

        // game over - life lost
        Point initPosGameOver;
        Point endPosGameOver;
        Rectangle dstRectGameOver;

        // score - label
        Vector2 initPosScore_Label;
        Vector2 endPosScore_Label;
        Vector2 posScore_Label;

        // score - value
        Vector2 initPosScore_Value;
        Vector2 endPosScore_Value;
        Vector2 posScore_Value;

        // lives - label
        Vector2 initPosLives_Label;
        Vector2 endPosLives_Label;
        Vector2 posLives_Label;

        // lives - value
        Vector2 initPosLives_Value;
        Vector2 endPosLives_Value;
        Vector2 posLives_Value;

        // background
        Texture2D bkgTex;
        Rectangle bkgRect;

        #endregion

        #region Screen Transitions

        bool toVisible = false;
        bool toHidden = false;
        float trTime = 0.0f;

        /// <summary>
        /// Makes the ScreenComponent2D transition to visible state.
        /// </summary>
        public override void Show()
        {
            toVisible = true;
        }

        /// <summary>
        /// Makes the ScreenComponent2D transition to hidden state.
        /// </summary>
        public override void Hide()
        {
            toHidden = true;
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of this class.
        /// </summary>
        /// <param name="screen">The Screen that this ScreenComponent2D is associated to.</param>
        public GameOverMenu(StarFoxScreen screen)
            : base(screen)
        {
            gameScore = Game.Services.GetService(typeof(GameScore)) as GameScore;
            if (gameScore == null)
                throw new InvalidOperationException("Service of type GameScores not found");

            spriteSheet = Game.Content.Load<SpriteSheet>(ContentSettings.GetAsset("MENU_SPRITES"));
            smallFont = Game.Content.Load<SpriteFont>(ContentSettings.GetAsset("FONT_SMALL"));

            Initialize_Menu();
            Initialize_Message();
            Initialize_Background();
        }

        #region Initialize_Menu

        private void Initialize_Menu()
        {
            Rectangle auxRect;

            // logo
            auxRect = spriteSheet.SourceRectangle("LOGO_STARFOX_SMALL");
            dstRectStarFox = new Rectangle((int)(0.675f * Screen.Width), (int)(0.75f * Screen.Height), (int)(auxRect.Width * Screen.Scale), (int)(auxRect.Height * Screen.Scale));
            auxRect = spriteSheet.SourceRectangle("LOGO_XNA_SMALL");
            dstRectXna = new Rectangle(0, 0, (int)(auxRect.Width * Screen.Scale), (int)(auxRect.Height * Screen.Scale));
            dstRectXna.Location = new Point(dstRectStarFox.Right - (int)(auxRect.Width * Screen.Scale), dstRectStarFox.Bottom + (int)(dstRectStarFox.Height * 0.75f));

            // title
            auxRect = spriteSheet.SourceRectangle("TITLE_MISSION_FAILED");
            dstRectMenuTitle = new Rectangle(0, 0, (int)(auxRect.Width * Screen.Scale), (int)(auxRect.Height * Screen.Scale));
            initPosMenuTitle = new Point((int)(Screen.Width * 0.05f), -dstRectMenuTitle.Height);
            endPosMenuTitle = new Point(initPosMenuTitle.X, (int)(Screen.Height * 0.06f));
            dstRectMenuTitle.Location = initPosMenuTitle;

            // buttons
            auxRect = spriteSheet.SourceRectangle("BUTTON_A");
            dstRectBtn = new Rectangle(0, 0, (int)(auxRect.Width * Screen.Scale), (int)(auxRect.Height * Screen.Scale));
            initPosBtn = new Point((int)(Screen.Width * 0.05f), Screen.Height);
            endPosBtn = new Point(initPosBtn.X, (int)(Screen.Height * 0.9f));
            dstRectBtn.Location = initPosBtn;

            // button messages
            auxRect = spriteSheet.SourceRectangle("BUTTON_ACCEPT");
            dstRectBtn_Msg = new Rectangle(0, 0, (int)(auxRect.Width * Screen.Scale), (int)(auxRect.Height * Screen.Scale));
            Point auxBtnGap = new Point((int)(Screen.Width * 0.05f), (int)((dstRectBtn_Msg.Height - dstRectBtn.Height) / 2));
            initPosBtn_Msg = new Point(initPosBtn.X + auxBtnGap.X, initPosBtn.Y - auxBtnGap.Y);
            endPosBtn_Msg = new Point(initPosBtn_Msg.X, endPosBtn.Y - auxBtnGap.Y);
            dstRectBtn_Msg.Location = initPosBtn_Msg;
        }

        #endregion

        #region Initialize_Message

        private void Initialize_Message()
        {
            Rectangle auxRect;
            Vector2 auxStrSize;

            // game over - life lost
            auxRect = (gameScore.Lives == 0) ? spriteSheet.SourceRectangle("ITEM_GAMEOVER") : spriteSheet.SourceRectangle("ITEM_LOSTLIFE");
            dstRectGameOver = new Rectangle(0, 0, (int)(auxRect.Width * Screen.Scale), (int)(auxRect.Height * Screen.Scale));
            initPosGameOver = new Point(-dstRectGameOver.Width, (int)(Screen.Height * 0.35f));
            endPosGameOver = new Point((int)((Screen.Width - dstRectGameOver.Width) * 0.5f), initPosGameOver.Y);
            dstRectGameOver.Location = initPosGameOver;

            // score - label
            auxStrSize = smallFont.MeasureString("SCORE") * Screen.Scale;
            initPosScore_Label = new Vector2(-2 * auxStrSize.X, Screen.Height * 0.45f);
            endPosScore_Label = new Vector2(Screen.Width * 0.45f - auxStrSize.X, initPosScore_Label.Y);
            posScore_Label = initPosScore_Label;

            // score - value
            auxStrSize = smallFont.MeasureString(ScoreToString(gameScore.Score)) * Screen.Scale;
            initPosScore_Value = new Vector2(Screen.Width + 2 * auxStrSize.X, Screen.Height * 0.45f);
            endPosScore_Value = new Vector2(Screen.Width * 0.55f, initPosScore_Value.Y);
            posScore_Value = initPosScore_Value;

            // lives - label
            auxStrSize = smallFont.MeasureString("LIVES") * Screen.Scale;
            initPosLives_Label = new Vector2(-2 * auxStrSize.X, Screen.Height * 0.55f);
            endPosLives_Label = new Vector2(Screen.Width * 0.45f - auxStrSize.X, initPosScore_Label.Y);
            posLives_Label = initPosLives_Label;

            // lives - value
            auxStrSize = smallFont.MeasureString(LivesToString(gameScore.Lives)) * Screen.Scale;
            initPosLives_Value = new Vector2(Screen.Width + 2 * auxStrSize.X, Screen.Height * 0.55f);
            endPosLives_Value = new Vector2(Screen.Width * 0.55f, initPosScore_Value.Y);
            posLives_Value = initPosLives_Value;
        }

        #endregion

        #region Initialize_Background

        private void Initialize_Background()
        {
            bkgTex = new Texture2D(Screen.GraphicsDevice, 1, 1);
            bkgTex.SetData(new[] { new Color(51, 51, 51, 191) });
            bkgRect = new Rectangle(0, (int)(Screen.Height * 0.30f), Screen.Width, (int)(Screen.Height * 0.34f));
        }

        #endregion

        #endregion

        #region Update

        /// <summary>
        /// Called when the ScreenComponent2D needs to be updated.
        /// </summary>
        /// <param name="gameTime">Time elapsed since the last call to this method.</param>
        public override void Update(GameTime gameTime)
        {
            #region Screen Transition

            if (toVisible)
            {
                // update items position
                float auxTrTime = 1.0f - (float)Math.Pow(1.0f - trTime, 2);
                // menu title
                dstRectMenuTitle.Y = initPosMenuTitle.Y + (int)(Math.Abs(initPosMenuTitle.Y - endPosMenuTitle.Y) * auxTrTime);
                // buttons
                dstRectBtn.Y = initPosBtn.Y - (int)(Math.Abs(initPosBtn.Y - endPosBtn.Y) * auxTrTime);
                dstRectBtn_Msg.Y = initPosBtn_Msg.Y - (int)(Math.Abs(initPosBtn_Msg.Y - endPosBtn_Msg.Y) * auxTrTime);
                // items
                dstRectGameOver.X = initPosGameOver.X + (int)(Math.Abs(initPosGameOver.X - endPosGameOver.X) * auxTrTime);
                posScore_Label.X = initPosScore_Label.X + Math.Abs(initPosScore_Label.X - endPosScore_Label.X) * auxTrTime;
                posScore_Value.X = initPosScore_Value.X - Math.Abs(initPosScore_Value.X - endPosScore_Value.X) * auxTrTime;
                posLives_Label.X = initPosLives_Label.X + Math.Abs(initPosLives_Label.X - endPosLives_Label.X) * auxTrTime;
                posLives_Value.X = initPosLives_Value.X - Math.Abs(initPosLives_Value.X - endPosLives_Value.X) * auxTrTime;

                // update transition timer
                float trDelta = (float)(gameTime.ElapsedGameTime.TotalMilliseconds / Time.TotalMilliseconds);
                trTime += trDelta;
                trTime = MathHelper.Clamp(trTime, 0.0f, 1.0f);
                if (trTime == 1.0f) { toVisible = false; trTime = 0.0f; }
            }
            else if (toHidden)
            {
                // update items position
                float auxTrTime = (float)Math.Pow(trTime, 2);
                // menu title
                dstRectMenuTitle.Y = endPosMenuTitle.Y - (int)(Math.Abs(initPosMenuTitle.Y - endPosMenuTitle.Y) * auxTrTime);
                // buttons
                dstRectBtn.Y = (int)(endPosBtn.Y + Math.Abs(initPosBtn.Y - endPosBtn.Y) * auxTrTime);
                dstRectBtn_Msg.Y = (int)(endPosBtn_Msg.Y + Math.Abs(initPosBtn_Msg.Y - endPosBtn_Msg.Y) * auxTrTime);
                // items
                dstRectGameOver.X = endPosGameOver.X - (int)(Math.Abs(initPosGameOver.X - endPosGameOver.X) * auxTrTime);
                posScore_Label.X = endPosScore_Label.X - Math.Abs(initPosScore_Label.X - endPosScore_Label.X) * auxTrTime;
                posScore_Value.X = endPosScore_Value.X + Math.Abs(initPosScore_Value.X - endPosScore_Value.X) * auxTrTime;
                posLives_Label.X = endPosLives_Label.X - Math.Abs(initPosLives_Label.X - endPosLives_Label.X) * auxTrTime;
                posLives_Value.X = endPosLives_Value.X + Math.Abs(initPosLives_Value.X - endPosLives_Value.X) * auxTrTime;

                // update transition timer
                float trDelta = (float)(gameTime.ElapsedGameTime.TotalMilliseconds / Time.TotalMilliseconds);
                trTime += trDelta;
                trTime = MathHelper.Clamp(trTime, 0.0f, 1.0f);
                if (trTime == 1.0f) { toHidden = false; trTime = 0.0f; }
            }

            #endregion

            #region Player Input

            if (Screen.InputEnabled)
            {
                if (Screen.PlayerInput.IsMenuSelect(Screen.PlayerIndex))
                {
                    if (gameScore.Lives == 0)
                    {
                        // go back to presentation screen 
                        Screen.ScreenManager.Clear(new PresentationScreen(Screen.ScreenManager));

                        // unload all per-screen loaded assets
                        Screen.Content.Unload();
                    }
                    else
                    {
                        // go back to gameplay screen 
                        Screen.ScreenManager.Clear(new IntroScreen(Screen.ScreenManager));
                    }
                }
            }

            #endregion
        }

        #endregion

        #region Draw

        /// <summary>
        /// Called when the ScreenComponent2D needs to be drawn.
        /// </summary>
        /// <param name="gameTime">Time elapsed since the last call to this method.</param>
        public override void Draw(GameTime gameTime)
        {
            // background
            SpriteBatch.Draw(bkgTex, bkgRect, Color.Yellow);

            // logo
            SpriteBatch.Draw(spriteSheet.Texture, dstRectStarFox, spriteSheet.SourceRectangle("LOGO_STARFOX_SMALL"), Color.Red);
            SpriteBatch.Draw(spriteSheet.Texture, dstRectXna, spriteSheet.SourceRectangle("LOGO_XNA_SMALL"), Color.Red);

            // title
            SpriteBatch.Draw(spriteSheet.Texture, dstRectMenuTitle, spriteSheet.SourceRectangle("TITLE_MISSION_FAILED"), Color.Yellow);

            // buttons
            SpriteBatch.Draw(spriteSheet.Texture, dstRectBtn, spriteSheet.SourceRectangle("BUTTON_A"), Color.GreenYellow);
            SpriteBatch.Draw(spriteSheet.Texture, dstRectBtn_Msg, spriteSheet.SourceRectangle("BUTTON_ACCEPT"), Color.Yellow);

            // items
            if (gameScore.Lives == 0)
            {
                SpriteBatch.Draw(spriteSheet.Texture, dstRectGameOver, spriteSheet.SourceRectangle("ITEM_GAMEOVER"), Color.Red);
            }
            else
            {
                SpriteBatch.Draw(spriteSheet.Texture, dstRectGameOver, spriteSheet.SourceRectangle("ITEM_LOSTLIFE"), Color.Red);
            }

            // items
            SpriteBatch.DrawString(smallFont, "SCORE", posScore_Label, Color.Yellow, 0, Vector2.Zero, Screen.Scale, SpriteEffects.None, 0);
            SpriteBatch.DrawString(smallFont, ScoreToString(gameScore.Score), posScore_Value, Color.Red, 0, Vector2.Zero, Screen.Scale, SpriteEffects.None, 0);
            SpriteBatch.DrawString(smallFont, "LIVES", posLives_Label, Color.Yellow, 0, Vector2.Zero, Screen.Scale, SpriteEffects.None, 0);
            SpriteBatch.DrawString(smallFont, LivesToString(gameScore.Lives), posLives_Value, Color.Red, 0, Vector2.Zero, Screen.Scale, SpriteEffects.None, 0);
        }

        private string ScoreToString(int score)
        {
            int length = score.ToString().Length;
            string str = string.Empty;

            for (int i = 0; i < (6 - length); i++) { str += "0"; }
            str += score.ToString();
            return str;
        }

        private string LivesToString(int lives)
        {
            int length = lives.ToString().Length;
            string str = string.Empty;

            for (int i = 0; i < (2 - length); i++) { str += "0"; }
            str += lives.ToString();
            return str;
        }

        #endregion
    }

    #endregion
}
